﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Phoenix.Xna.Framework.FrameworkExtensions;
using Phoenix.Xna.Framework.Properties;

namespace Phoenix.Xna.Framework.Xml
{
    public static class XElementExtensions
    {
        public static bool ContainsAttribute(this XElement element, string attribute)
        {
            return (element.Attribute(attribute) == null) ? false : true;
        }

        public static T ReadAttribute<T>(this XElement element, string attribute)
        {
            if (element.ContainsAttribute(attribute))
            {
                if (typeof(T) != typeof(string))
                {
                    return (element.Attribute(attribute).Value).ParseT<T>();
                }
                else
                {
                    object value = element.Attribute(attribute).Value;
                    return (T)value;
                }
            }

            return default(T);
        }

        public static T ReadAttribute<T>(this XElement element, string attribute, T defaultValue)
        {
            if (element.ContainsAttribute(attribute))
            {
                string value = element.Attribute(attribute).Value;

                if (!string.IsNullOrEmpty(value))
                {
                    if (typeof(T) != typeof(string))
                    {
                        return value.ParseT<T>();
                    }
                    else
                    {
                        return (T)((object)value);
                    }
                }
            }

            return defaultValue;
        }

        public static N ReadAttribute<N, T>(this XElement element, string attribute, N defaultValue)
        {
            if (element.ContainsAttribute(attribute))
            {
                string value = element.Attribute(attribute).Value;

                if (!string.IsNullOrEmpty(value))
                {
                    if (typeof(T) != typeof(string))
                    {
                        object data = value.ParseT<T>();
                        return (N)data;
                    }
                    else
                    {
                        return (N)((object)value);
                    }
                }
            }

            return defaultValue;
        }

        public static T ReadValue<T>(this XElement element)
        {
            if (typeof(T) != typeof(string))
            {
                return element.Value.ParseT<T>();
            }
            else
            {
                object data = element.Value;
                return (T)data;
            }
        }

        public static void ReadValue<T>(this XElement element, Action<T> action)
        {
            T data = ReadValue<T>(element);
            action(data);
        }

        public static T ReadValue<T>(this XElement element, T defaultValue)
        {
            if (!string.IsNullOrEmpty(element.Value))
            {
                return ReadValue<T>(element);
            }

            return defaultValue;
        }

        public static object ReadValue(this XElement element, string type)
        {
            if (string.Compare(type, "string", true) == 0)
            {
                return element.Value;
            }
            else if (string.Compare(type, "string[]", true) == 0)
            {
                return element.Value.Split(',');
            }
            else if (string.Compare(type, "bool", true) == 0)
            {
                return element.Value.ParseT<bool>();
            }
            else if (string.Compare(type, "bool[]", true) == 0)
            {
                string[] split = element.Value.Split(',');
                List<bool> data = new List<bool>();

                for (int i = 0; i < split.Length; i++)
                {
                    data.Add(split[i].ParseT<bool>());
                }

                return data.ToArray();
            }
            else if (string.Compare(type, "int", true) == 0)
            {
                return element.Value.ParseT<int>();
            }
            else if (string.Compare(type, "int[]", true) == 0)
            {
                string[] split = element.Value.Split(',');
                List<int> data = new List<int>();

                for (int i = 0; i < split.Length; i++)
                {
                    data.Add(split[i].ParseT<int>());
                }

                return data.ToArray();
            }
            else if (string.Compare(type, "float", true) == 0)
            {
                return element.Value.ParseT<float>();
            }
            else if (string.Compare(type, "float", true) == 0)
            {
                string[] split = element.Value.Split(',');
                List<float> data = new List<float>();

                for (int i = 0; i < split.Length; i++)
                {
                    data.Add(split[i].ParseT<float>());
                }

                return data.ToArray();
            }
            else if (string.Compare(type, "short", true) == 0)
            {
                return element.Value.ParseT<short>();
            }
            else if (string.Compare(type, "short", true) == 0)
            {
                string[] split = element.Value.Split(',');
                List<short> data = new List<short>();

                for (int i = 0; i < split.Length; i++)
                {
                    data.Add(split[i].ParseT<short>());
                }

                return data.ToArray();
            }
            else if (string.Compare(type, "double", true) == 0)
            {
                return element.Value.ParseT<double>();
            }
            else if (string.Compare(type, "double", true) == 0)
            {
                string[] split = element.Value.Split(',');
                List<double> data = new List<double>();

                for (int i = 0; i < split.Length; i++)
                {
                    data.Add(split[i].ParseT<double>());
                }

                return data.ToArray();
            }
            else if (string.Compare(type, "Vector2", true) == 0)
            {
                return element.Value.ParseT<Vector2>();
            }
            else if (string.Compare(type, "Vector2[]", true) == 0)
            {
                string[] split = element.Value.Split('|');
                List<Vector2> data = new List<Vector2>();

                for (int i = 0; i < split.Length; i++)
                {
                    data.Add(split[i].ParseT<Vector2>());
                }

                return data.ToArray();
            }
            else if (string.Compare(type, "Vector3", true) == 0)
            {
                return element.Value.ParseT<Vector3>();
            }
            else if (string.Compare(type, "Vector3[]", true) == 0)
            {
                string[] split = element.Value.Split('|');
                List<Vector3> data = new List<Vector3>();

                for (int i = 0; i < split.Length; i++)
                {
                    data.Add(split[i].ParseT<Vector3>());
                }

                return data.ToArray();
            }
            else if (string.Compare(type, "Vector4", true) == 0)
            {
                return element.Value.ParseT<Vector4>();
            }
            else if (string.Compare(type, "Vector4[]", true) == 0)
            {
                string[] split = element.Value.Split('|');
                List<Vector4> data = new List<Vector4>();

                for (int i = 0; i < split.Length; i++)
                {
                    data.Add(split[i].ParseT<Vector4>());
                }

                return data.ToArray();
            }
            else if (string.Compare(type, "Texture2D", true) == 0 ||
                string.Compare(type, "Texture2D[]", true) == 0 ||
                string.Compare(type, "Model", true) == 0 ||
                string.Compare(type, "Model[]", true) == 0 ||
                string.Compare(type, "InstancedModel", true) == 0 ||
                string.Compare(type, "InstancedModel[]", true) == 0)
            {
                return element.Value;
            }
            else
            {
                throw new NotSupportedException(string.Format(Resources.NotSupportedException, string.Format("'Create object of type {0} from xml.'", type)));
            }
        }

        public static void SetAttribute(this XElement element, string attribute, object value)
        {
            element.SetAttributeValue(attribute, StringHelper.ObjectToString(value));
        }
    }
}
